#include "camerathread.h"
#include "capturemanager.h"
#include "cvmanager.h"
#include "colorhistogram.h"
#include "logger.h"
#include <iostream>

using namespace controllers;
using namespace utilities;
using namespace std;

CameraThread::CameraThread(QObject *parent) :
    QThread(parent),
    _frames(0),
    _threshold(-1.0),
    _referenceTaken(false),
    _recordingVideo(false),
    _objectDetected(false),
    _processingObject(false)
{
    _imageComparator            = new ImageComparator();
    _dbImageHistograms          = new QVector<MatND>();
    _dbImageHueHistograms       = new QVector<MatND>();
    _dbImageSParseHistograms    = new QVector<SparseMat>();
}

CameraThread::~CameraThread()
{
    delete _imageComparator;
    delete _dbImageHistograms;
}

void CameraThread::run()
{
    Logger::logMessage("CameraThread::run(): Camera image feed starting...");

    int camera_index = 0, c, r, index = -1, cpt = 0, refFrames = 0;
    Mat frame, imageROI, waitRefImg, detectedImg;
    QTime timer;
    int currTime;

    QString waitRef[3] = {"F:/Adama/Session Hiver 2014/LOG792/Remises/code/Recyk/Data/img/waitRef1.png",
                          "F:/Adama/Session Hiver 2014/LOG792/Remises/code/Recyk/Data/img/waitRef2.png",
                          "F:/Adama/Session Hiver 2014/LOG792/Remises/code/Recyk/Data/img/waitRef3.png"};
    QImage qImage;
    CaptureManager cm(camera_index);

    while (true)
    {
        // Capture a frame
        _currentFrame   = *(cm.captureMatImage());
        //_currentFrame.convertTo(_currentFrame, -1, 1, 100); // set the contraste

        if (!_referenceTaken)
        {
            frame = _currentFrame;
            // Set index of wait ref image
            if (cpt == 0)
            {
                index++;
                index = index % 3;
            }
            cpt = ++cpt % 10;

            // Read logo
            waitRefImg = imread(waitRef[index].toStdString());

            // define ROI
            c = (_currentFrame.cols / 2) - (waitRefImg.cols / 2);
            r = _currentFrame.rows - waitRefImg.rows - 50;
            CVManager::watermarkImage(_currentFrame, waitRefImg, c, r);

            // Frame number at which the reference image is taken
            refFrames = _frames + 1;
        }
        else
        {
            if (_threshold == -1.0)
            {
                // Save histogram comparison reference value (by comparing the reference frame's histogram to itself)
                _threshold = _imageComparator->compareWithRefWithRef(HUE);
            }
            else
            {
                // Detect object presence by comparing current frame with the frame of reference (background)
                currTime = timer.elapsed();

                double compResult = _imageComparator->compareWithReference(_currentFrame, HUE);
                cout << "  in " << timer.elapsed() - currTime << " milliseconds" << endl;

                double diff = _threshold - compResult;
                cout << "Comp. with histRef: " << compResult << endl;
                cout << "Diff. with threshold: " << diff << endl;


                if (abs(diff) > HUE_COMPARISON_THRESHOLD)
                {
                    cout << "Object presence is detected" << endl;
                    _objectDetected = true;

                    detectedImg = imread("../Recyk/Data/img/detected.png");
                    c = 20;
                    r = 20;
                    CVManager::watermarkImage(_currentFrame, detectedImg, c, r);

                    if (_processingObject)
                    {
                        cout << "Processing object" << endl;

                        // Get the histogram of the current frame (object)
                        /*ColorHistogram cHist;
                        SparseMat objectHist(cHist.getHueHistogram(_currentFrame));
                        SparseMat dbHist;*/
                        int i = 0;
                        double diff2;

                        Mat dbImage;
                        Mat object_recognized;

                        /*while (i < _dbImageHueHistograms->size())
                        {
                            dbHist = _dbImageHueHistograms->at(i);
                            // Compare the object's histogram with those in the DB list
                            diff2 = _imageComparator->compareHistograms(objectHist, dbHist, HUE);
                            cout << "A i=" << i << ", diff2=" << diff2 << endl;

                            i++;
                            sleep(1);
                        }*/
                        while (i < _dbImages.size() && _processingObject == true)
                        {
                            dbImage = _dbImageHueHistograms->at(i);

                            Mat img1 = imread( "F:/Adama/Session Hiver 2014/LOG792/Remises/code/Recyk/data/imgDB/tests/1.png");
                            Mat img2 = imread( "F:/Adama/Session Hiver 2014/LOG792/Remises/code/Recyk/data/imgDB/5.png");
                            // Find the features
                            object_recognized = CVManager::findFeatures(img1, img2);
                            //object_recognized = CVManager::findFeatures(dbImage, _currentFrame);

                            if (object_recognized.size().width != 0) // Empty image
                            {
                                _processingObject = false;
                            }

                            i++;
                            sleep(1);
                        }
                        //_processingObject = false;
                        if (!_processingObject)
                        {
                            qImage  = CVManager::matToQImage(object_recognized, _recognitionView->getFrameSize());
                            _recognitionView->setFrame2(qImage);
                        }
                        else
                        {
                            Mat notRecognizedImg = imread("../Recyk/Data/img/notRecognized.png");
                            c = 100;
                            r = 150;
                            CVManager::watermarkImage(_currentFrame, notRecognizedImg, c, r);
                        }

                    }
                    //CVManager::computeCanny(_currentFrame, _currentFrame);
                    //CVManager::computeLaplacian(_currentFrame, _currentFrame, 7);
                }
                else if (_objectDetected)
                {
                    _objectDetected   = false;
                    _processingObject = false;
                    cout << "Object has been removed" << endl;
                }
            }
        }

        // Display image
        //pyrDown( _currentFrame, _currentFrame, Size( frame.cols/2, frame.rows/2 ) );
        qImage  = CVManager::matToQImage(_currentFrame, _recognitionView->getFrameSize());
        _recognitionView->setFrame(qImage);

        // One more frame
        _frames++;
        //sleep(1);
    }
}

void CameraThread::setView(RecognitionView* rv)
{
    Logger::logMessage("CameraThread::setView(RecognitionView* rv)");
    _recognitionView = rv;
}

void CameraThread::saveReferenceImage()
{
    Logger::logMessage("CameraThread::saveReferenceImage()");
    if (_frames > 0)
    {
        Mat frame(_currentFrame);
        _imageComparator->setReferenceImage(frame);

        _referenceTaken = true;
        _threshold      = -1.0;
    }
}

void CameraThread::recordVideo()
{
    Logger::logMessage("CameraThread::recordVideo()");
}

void CameraThread::takeSnapshotImage()
{
    Logger::logMessage("CameraThread::takeSnapshotImage()");

    if (_frames > 0)
    {
        Mat frame(_currentFrame);
        QImage image = CVManager::matToQImage(frame, _recognitionView->getFrameSize());

        // Save the image
        _recognitionView->saveSnapshot(image);
    }
}

void CameraThread::startObjectRecognition()
{
    Logger::logMessage("CameraThread::startObjectRecognition()");
    if (_frames > 0)
        _processingObject = true;
}

void CameraThread::computeDBImageHistograms(QVector<Mat> images)
{
    ColorHistogram cHist;

    foreach (Mat img, images) {
        _dbImageHistograms->append(cHist.getHistogram(img));
        _dbImageHueHistograms->append(cHist.getHueHistogram(img));
        _dbImageSParseHistograms->append(cHist.getSparseHistogram(img));
    }

    // Save images
    _dbImages = images;
}
